package com.ww.springboot.mybatis.data.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ww.springboot.mybatis.common.en.StoreTypeEnum;
import com.ww.springboot.mybatis.data.entity.OnlineChannelServiceBindEntity;
import com.ww.springboot.mybatis.data.entity.OnlineChannelServiceBindStoreEntity;
import com.ww.springboot.mybatis.data.service.IOnlineChannelServiceBindService;
import com.ww.springboot.mybatis.data.service.IOnlineChannelServiceBindStoreService;
import com.ww.springboot.mybatis.dto.ChannelDTO;
import com.ww.springboot.mybatis.dto.OnlineChannelServiceBindDTO;
import com.ww.springboot.mybatis.dto.OnlineChannelServiceBindFindDTO;
import com.ww.springboot.mybatis.mapper.OnlineChannelServiceBindMapper;
import com.ww.springboot.mybatis.po.OnlineChannelServiceBindPO;
import com.ww.springboot.mybatis.util.AssertUtil;
import com.ww.springboot.mybatis.util.ExceptionUtil;
import com.ww.springboot.mybatis.util.Func;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.DateUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 服务实现类
 *
 * @author Chill
 */
@Service
@AllArgsConstructor
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class OnlineChannelServiceBindServiceImpl extends ServiceImpl<OnlineChannelServiceBindMapper,
        OnlineChannelServiceBindEntity> implements IOnlineChannelServiceBindService {

    private final IOnlineChannelServiceBindStoreService bindStoreService;

    /**
     * 保存线上绑定数据
     *
     * @param bindDTO 入参DTO
     * @return true成功  false失败
     */
    @Override
    public boolean save(OnlineChannelServiceBindDTO bindDTO) {
        // 校验和数据库是否重复
        this.checkFromDb(bindDTO);

        // 保存信息，分开多个渠道id存储
        bindDTO.getChannels().forEach(channel -> {
            OnlineChannelServiceBindEntity bind = BeanUtil.copyProperties(bindDTO, OnlineChannelServiceBindEntity.class);
            bind.setChannelId(channel.getId());
            bind.setChannelCode(channel.getChannelCode());
            // 保存主表
            boolean flag = super.save(bind);
            ExceptionUtil.checkData(Boolean.FALSE.equals(flag), "保存线上渠道绑定数据失败");
            // 保存店铺表数据
            this.saveOtherData(bindDTO, bind);
        });
        return true;
    }

    /**
     * 编辑
     *
     * @param bindDTO 线上绑定服务DTO
     * @return true 成功  false 失败
     */
    @Override
    public boolean updateById(OnlineChannelServiceBindDTO bindDTO) {
        // 原主表信息(记录更新前信息)
        OnlineChannelServiceBindEntity oldBind = super.getById(bindDTO.getId());
        // 保存主表信息
        updateBind(bindDTO);
        // 删除店铺信息
        bindStoreService.deleteByOcsbIds(bindDTO.getId().toString());
        // 保存店铺表数据
        this.saveOtherData(bindDTO, oldBind);

        return true;
    }

    private void updateBind(OnlineChannelServiceBindDTO bindDTO) {
        OnlineChannelServiceBindEntity bind = BeanUtil.copyProperties(bindDTO, OnlineChannelServiceBindEntity.class);
        int i = baseMapper.update(bind, Wrappers.<OnlineChannelServiceBindEntity>lambdaUpdate()
                .set(OnlineChannelServiceBindEntity::getFreightLow, bind.getFreightLow())
                .set(OnlineChannelServiceBindEntity::getFreightHigh, bind.getFreightHigh())
                .set(OnlineChannelServiceBindEntity::getPriceLow, bind.getPriceLow())
                .set(OnlineChannelServiceBindEntity::getPriceHigh, bind.getPriceHigh())
                .set(OnlineChannelServiceBindEntity::getTotalPriceLow, bind.getTotalPriceLow())
                .set(OnlineChannelServiceBindEntity::getTotalPriceHigh, bind.getTotalPriceHigh())
                .eq(OnlineChannelServiceBindEntity::getId, bind.getId())
        );
        ExceptionUtil.checkData(Boolean.FALSE.equals(i > 0), "更新店铺信息失败");
    }


    /**
     * 删除
     *
     * @param ids 主表id 多个用“,”分割
     * @return true 成功 false 失败
     */
    @Override
    public boolean deleteAll(String ids) {
        // 删除主表
        boolean flag = this.deleteBatchByIds(Func.toLongList(ids));
        ExceptionUtil.checkData(Boolean.FALSE.equals(flag), "删除信息失败");
        // 删除店铺子表(物理删除)
        bindStoreService.deleteByOcsbIds(ids);
        return true;
    }

    /**
     * 根据筛选条件获取合适的渠道
     *
     * @param findDTO 筛选条件
     * @return 渠道列表
     */
    @Override
    public List<Long> getChannelId(OnlineChannelServiceBindFindDTO findDTO) {
        List<Long> channelList = new ArrayList<>();
        //查出所有符合条件的渠道 --不包含店铺条件
        List<OnlineChannelServiceBindEntity> bindEntities = baseMapper.getChannelId(findDTO);
        //根据店铺类型分组
        Map<Integer, List<OnlineChannelServiceBindEntity>> map = bindEntities.stream()
                .collect(Collectors.groupingBy(OnlineChannelServiceBindEntity::getStoreType));

        map.forEach((k, v) -> {
            //原channelIds
            List<Long> channelIds = v.stream().map(OnlineChannelServiceBindEntity::getChannelId).collect(Collectors.toList());
            //数据库中根据店铺查询到的channelIds
            List<Long> findChannelIds = getFindChannelIds(findDTO, v);
            switch (StoreTypeEnum.getByValue(k)) {
                case ALL:
                    channelList.addAll(channelIds);
                    break;
                case WHITE_LIST:
                    if (ObjectUtil.isNotEmpty(findChannelIds)) {
                        channelList.addAll(findChannelIds);
                    }
                    break;
                case BLACK_LIST:
                    if (ObjectUtil.isNotEmpty(findChannelIds)) {
                        //去除黑名单内channelIds
                        channelIds.removeAll(findChannelIds);
                    }
                    channelList.addAll(channelIds);
                    break;
                default:
                    break;
            }
        });
        return channelList;
    }

    private List<Long> getFindChannelIds(OnlineChannelServiceBindFindDTO findDTO, List<OnlineChannelServiceBindEntity> v) {
        //绑定服务id
        List<Long> ocsbIds = v.stream().map(OnlineChannelServiceBindEntity::getId).collect(Collectors.toList());
        //过滤店铺数据
        List<OnlineChannelServiceBindStoreEntity> storeEntities = bindStoreService.getByStoreCode(ocsbIds, findDTO.getStoreCode());
        //查询到的渠道ids
        return storeEntities.stream().map(OnlineChannelServiceBindStoreEntity::getChannelId)
                .distinct().collect(Collectors.toList());
    }

    /**
     * 根据id的集合批量删除
     *
     * @param ids id集合
     * @return true 删除成功 false 删除失败
     */
    @Override
    public boolean deleteBatchByIds(List<Long> ids) {
        return baseMapper.deleteBatchByIds(0L, DateUtil.now(), ids) > 0;
    }

    /**
     * 校验和数据库是否重复
     *
     * @param bindDTO dto
     */
    private void checkFromDb(OnlineChannelServiceBindDTO bindDTO) {
        List<String> channelCodes = bindDTO.getChannels().stream().map(ChannelDTO::getChannelCode).collect(Collectors.toList());
        ExceptionUtil.checkArgument(channelCodes.size() < 1, "渠道编码获取异常");

        // 线上服务名 +渠道名称不能重复
        List<OnlineChannelServiceBindEntity> list = lambdaQuery()
                .eq(OnlineChannelServiceBindEntity::getOcsId, bindDTO.getOcsId())
                .in(OnlineChannelServiceBindEntity::getChannelCode, channelCodes)
                .list();
        if (CollUtil.isNotEmpty(list)) {
            // 记录重复的渠道集合
            List<String> repeatList = new LinkedList<>();
            list.forEach(o -> {
                repeatList.add(o.getChannelId().toString());
            });
            throw new RuntimeException(Func.join(repeatList) + "，渠道绑定重复");
        }
    }

    /**
     * 保存店铺表数据
     *
     * @param bindDTO dto
     * @param bind    实体
     */
    private void saveOtherData(OnlineChannelServiceBindDTO bindDTO, OnlineChannelServiceBindEntity bind) {
        //全部店铺 不存店铺信息
        if (StoreTypeEnum.ALL.getValue().equals(bindDTO.getStoreType())) {
            return;
        }
        AssertUtil.notEmpty(bindDTO.getOnlineChannelServiceBindStoreDTOList(), "店铺不能为空");
        // 保存店铺表信息
        List<OnlineChannelServiceBindStoreEntity> stores = new ArrayList<>();
        bindDTO.getOnlineChannelServiceBindStoreDTOList().forEach(dto -> {
            OnlineChannelServiceBindStoreEntity store = BeanUtil.copyProperties(dto, OnlineChannelServiceBindStoreEntity.class);
            ExceptionUtil.checkData(store == null, "转换实体失败");
            store.setStoreCode(dto.getStoreCode());
            store.setChannelId(bind.getChannelId());
            store.setChannelCode(bind.getChannelCode());
            store.setOcsId(bind.getOcsId());
            store.setOcsbId(bind.getId());
            store.setPlatformId(bindDTO.getPlatformId());
            store.setPlatformCode(bindDTO.getPlatformCode());
            stores.add(store);
        });
        boolean flag2 = bindStoreService.insertBatch(stores);
        ExceptionUtil.checkData(Boolean.FALSE.equals(flag2), "更新新店铺信息失败");
    }

    /**
     * 查询线上服务绑定列表
     *
     * @param id 筛选条件
     * @return 线上绑定数据
     */
    @Override
    public List<OnlineChannelServiceBindPO> selectAllList(Long id) {
        return baseMapper.selectAllList(id);
    }

    @Override
    public List<OnlineChannelServiceBindEntity> getByOcsIdAndChannels(Long ocsId, List<Long> channelIds) {
        return lambdaQuery()
                .eq(OnlineChannelServiceBindEntity::getOcsId, ocsId)
                .in(OnlineChannelServiceBindEntity::getChannelId, channelIds)
                .list();
    }
}
